package pro.cherish.knowledgedemoaop.aop;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 创建人：cherish
 * @version 版本号：V1.0
 * <p>
 * ***************************修订记录************************************
 * 2019-09-28 cherish 创建该类功能。
 * **********************************************************************
 * </p>
 * @ClassName 类名：WebLogAcpect2
 * @Description 功能说明：
 * <p>
 * TODO
 * </p>
 * **********************************************************************
 * @date 创建日期： 2019-09-28 cherish
 */
@Aspect
@Component
@Slf4j
public class WebLogAcpect2 {
    /**
     * 定义切入点，切入点为com.example.aop下的所有函数
     */
    @Pointcut("execution(public * pro.cherish.knowledgedemoaop.controller.Tcontroller2.*(..))")
    public void webLog() {
    }

    /**
     * 前置通知，方法调用前被调用
     *
     * @param joinPoint/null
     */
    @Before(value = "webLog()")
    public void before(JoinPoint joinPoint) throws JsonProcessingException {
        log.info("前置通知");
        //获取目标方法的参数信息  
        Object[] obj = joinPoint.getArgs();
        //AOP代理类的信息  
        Object aThis = joinPoint.getThis();
        //代理的目标对象  
        Object target = joinPoint.getTarget();
        //用的最多 通知的签名  
        Signature signature = joinPoint.getSignature();
        //代理的是哪一个方法  
        log.info("代理的是哪一个方法" + signature.getName());
        //AOP代理类的名字  
        log.info("AOP代理类的名字" + signature.getDeclaringTypeName());
        //AOP代理类的类（class）信息  
        Class declaringType = signature.getDeclaringType();
        //获取RequestAttributes  
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        //从获取RequestAttributes中获取HttpServletRequest的信息  
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        //如果要获取Session信息的话，可以这样写：  
        //HttpSession session = (HttpSession) requestAttributes.resolveReference(RequestAttributes.REFERENCE_SESSION);  
        //获取请求参数
        Enumeration<String> enumeration = request.getParameterNames();
        Map<String, String> parameterMap = new HashMap<>(0);
        while (enumeration.hasMoreElements()) {
            String parameter = enumeration.nextElement();
            parameterMap.put(parameter, request.getParameter(parameter));
        }
        ObjectMapper objectMapper = new ObjectMapper();
        String str = objectMapper.writeValueAsString(parameterMap);
        if (obj.length > 0) {
            log.info("请求的参数信息为：" + str);
        }
    }


    /**
     * 后置返回通知
     * 这里需要注意的是:
     * 如果参数中的第一个参数为JoinPoint，则第二个参数为返回值的信息
     * 如果参数中的第一个参数不为JoinPoint，则第一个参数为returning中对应的参数
     * returning：限定了只有目标方法返回值与通知方法相应参数类型 相同时才能执行后置返回通知，否则不执行，
     * 对于returning对应的通知方法参数为Object类型将匹配任何目标返回值
     *
     * @param joinPoint
     * @param keys
     */
    @AfterReturning(value = "webLog()", returning = "keys")
    public void doAfterReturningAdvice1(JoinPoint joinPoint, Object keys) {
        log.info("第一个后置返回通知的返回值：" + keys);
    }

    @AfterReturning(value = "webLog()", returning = "keys", argNames = "keys")
    public void doAfterReturningAdvice2(String keys) {
        log.info("第二个后置返回通知的返回值：" + keys);
    }
}
